﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using IPC.Communication.Framework.BasicFramework;
using IPC.Communication.Framework.Core;
using IPC.Communication.Framework.Reflection;
using IPC.Communication.Framework.Serial;

namespace IPC.Communication.Framework.Profinet.Omron
{
    public class OmronHostLink : SerialDeviceBase
    {
        private byte _icf = 0;
        private byte _da2 = 0;
        private byte _sid = 0;
        private byte _responseWaitTime = 48;
        private int _readSplits = 260;
        public byte ICF
        {
            get { return _icf; }
            set { _icf = value; }
        }


        public byte DA2
        {
            get { return _da2; }
            set { _da2 = value; }
        }


        public byte SA2
        {
            get;
            set;
        }

        public byte SID
        {
            get { return _sid; }
            set { _sid = value; }
        }


        public byte ResponseWaitTime
        {
            get { return _responseWaitTime; }
            set { _responseWaitTime = value; }
        }


        public byte UnitNumber
        {
            get;
            set;
        }

        public int ReadSplits
        {
            get { return _readSplits; }
            set { _readSplits = value; }
        }


        public OmronHostLink()
        {
            base.ByteTransform = new ReverseWordTransform();
            base.WordLength = 1;
            base.ByteTransform.DataFormat = DataFormat.CDAB;
            base.ByteTransform.IsStringReverseByteWord = true;
            LogMsgFormatBinary = false;
        }

        protected override OperateResult<byte[]> UnpackResponseContent(byte[] send, byte[] response)
        {
            return OmronHostLinkOverTcp.ResponseValidAnalysis(send, response);
        }

        public override void SerialPortInni(string portName)
        {
            base.SerialPortInni(portName);
        }

        public override void SerialPortInni(string portName, int baudRate)
        {
            base.SerialPortInni(portName, baudRate, 7, StopBits.One, Parity.Even);
        }

        [HslMqttApi("ReadByteArray", "")]
        public override OperateResult<byte[]> Read(string address, ushort length)
        {
            byte station = (byte)HslHelper.ExtractParameter(ref address, "s", UnitNumber);
            bool isBit = false;
            OperateResult<List<byte[]>> operateResult = OmronFinsNetHelper.BuildReadCommand(address, length, isBit = false, ReadSplits);
            if (!operateResult.IsSuccess)
            {
                return operateResult.ConvertFailed<byte[]>();
            }
            List<byte> list = new List<byte>();
            for (int i = 0; i < operateResult.Content.Count; i++)
            {
                OperateResult<byte[]> operateResult2 = ReadFromCoreServer(PackCommand(station, operateResult.Content[i]));
                if (!operateResult2.IsSuccess)
                {
                    return OperateResult.CreateFailedResult<byte[]>(operateResult2);
                }
                list.AddRange(operateResult2.Content);
            }
            return OperateResult.CreateSuccessResult(list.ToArray());
        }

        [HslMqttApi("WriteByteArray", "")]
        public override OperateResult Write(string address, byte[] value)
        {
            byte station = (byte)HslHelper.ExtractParameter(ref address, "s", UnitNumber);
            OperateResult<byte[]> operateResult = OmronFinsNetHelper.BuildWriteWordCommand(address, value, isBit: false);
            if (!operateResult.IsSuccess)
            {
                return operateResult;
            }
            OperateResult<byte[]> operateResult2 = ReadFromCoreServer(PackCommand(station, operateResult.Content));
            if (!operateResult2.IsSuccess)
            {
                return operateResult2;
            }
            return OperateResult.CreateSuccessResult();
        }

        [HslMqttApi("ReadBoolArray", "")]
        public override OperateResult<bool[]> ReadBool(string address, ushort length)
        {
            byte station = (byte)HslHelper.ExtractParameter(ref address, "s", UnitNumber);
            OperateResult<List<byte[]>> operateResult = OmronFinsNetHelper.BuildReadCommand(address, length, isBit: true);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<bool[]>(operateResult);
            }
            List<bool> list = new List<bool>();
            for (int i = 0; i < operateResult.Content.Count; i++)
            {
                OperateResult<byte[]> operateResult2 = ReadFromCoreServer(PackCommand(station, operateResult.Content[i]));
                if (!operateResult2.IsSuccess)
                {
                    return OperateResult.CreateFailedResult<bool[]>(operateResult2);
                }
                list.AddRange(operateResult2.Content.Select((byte m) => (m != 0) ? true : false));
            }
            return OperateResult.CreateSuccessResult(list.ToArray());
        }

        [HslMqttApi("WriteBoolArray", "")]
        public override OperateResult Write(string address, bool[] values)
        {
            byte station = (byte)HslHelper.ExtractParameter(ref address, "s", UnitNumber);
            OperateResult<byte[]> operateResult = OmronFinsNetHelper.BuildWriteWordCommand(address, values.Select((bool m) => (byte)(m ? 1 : 0)).ToArray(), isBit: true);
            if (!operateResult.IsSuccess)
            {
                return operateResult;
            }
            OperateResult<byte[]> operateResult2 = ReadFromCoreServer(PackCommand(station, operateResult.Content));
            if (!operateResult2.IsSuccess)
            {
                return operateResult2;
            }
            return OperateResult.CreateSuccessResult();
        }

        public override string ToString()
        {
            return String.Format("OmronHostLink[{0}:{1}]", base.PortName, base.BaudRate);
        }

        private byte[] PackCommand(byte station, byte[] cmd)
        {
            cmd = SoftBasic.BytesToAsciiBytes(cmd);
            byte[] array = new byte[18 + cmd.Length];
            array[0] = 64;
            array[1] = SoftBasic.BuildAsciiBytesFrom(station)[0];
            array[2] = SoftBasic.BuildAsciiBytesFrom(station)[1];
            array[3] = 70;
            array[4] = 65;
            array[5] = ResponseWaitTime;
            array[6] = SoftBasic.BuildAsciiBytesFrom(ICF)[0];
            array[7] = SoftBasic.BuildAsciiBytesFrom(ICF)[1];
            array[8] = SoftBasic.BuildAsciiBytesFrom(DA2)[0];
            array[9] = SoftBasic.BuildAsciiBytesFrom(DA2)[1];
            array[10] = SoftBasic.BuildAsciiBytesFrom(SA2)[0];
            array[11] = SoftBasic.BuildAsciiBytesFrom(SA2)[1];
            array[12] = SoftBasic.BuildAsciiBytesFrom(SID)[0];
            array[13] = SoftBasic.BuildAsciiBytesFrom(SID)[1];
            array[array.Length - 2] = 42;
            array[array.Length - 1] = 13;
            cmd.CopyTo(array, 14);
            int num = array[0];
            for (int i = 1; i < array.Length - 4; i++)
            {
                num ^= array[i];
            }
            array[array.Length - 4] = SoftBasic.BuildAsciiBytesFrom((byte)num)[0];
            array[array.Length - 3] = SoftBasic.BuildAsciiBytesFrom((byte)num)[1];
            return array;
        }
    }
}
